package com.kcs.common.framework;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import com.kcs.common.utils.Constant;
import com.kcs.common.utils.EventFactory;
import com.kcs.common.utils.LogWriter;

public abstract class GenericAbstractAction extends Action {
										
	protected boolean checkTransition(ActionForm form,
			HttpServletRequest request) throws Exception {

		GenericForm srcform = null;

		try {

			srcform = (GenericForm) form;

			if (form instanceof com.kcs.dc.report.view.form.LoginForm) {
				// 1st time

				// get operation time and set to session and jsp(action form)
				setOpeTime(srcform, request);

			} else {
				// After 2nd time
				if (checkPrevOpeTime(srcform, request)) {
					// get operation time and set to session and jsp(action
					// form)
					setOpeTime(srcform, request);
				} else {
					// Unaccaptable screen transition error
					// CommonUtil.setMessageToForm(srcform,Constant.ERR_TRANSITION);
					return false;
				}

			}

		} catch (Exception e) {
			throw new Exception();
		}
		return true;

	}

	private boolean checkPrevOpeTime(GenericForm srcform,
			HttpServletRequest request) {
		String sessionValue = null;
		String requestValue = null;

		// get pre operation time from session and http request
		requestValue = srcform.getOperationTime();
		sessionValue = (String) request.getSession().getAttribute(Constant.SESSION_PREOPETIME);

		// if both value is same, return true;
		return sessionValue.equals(requestValue);
	}

	private void setOpeTime(GenericForm srcform, HttpServletRequest request) {
		String opeTime = null;
		// get operation time
		opeTime = Long.toString(System.currentTimeMillis());

		// set session and jsp (action form) to control transaction for next
		// request
		srcform.setOperationTime(opeTime);
		request.getSession().setAttribute(Constant.SESSION_PREOPETIME, opeTime);
	}

	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {

		ActionForward af = null;
		String executeType = null;
		String prevOpeTime = null;
		GenericForm gForm = null;

		try { 
			
				// Check session timeout
				if (request.getSession().getAttribute(Constant.SESSION_USERID) == null
						&& !(form instanceof com.kcs.dc.report.view.form.LoginForm)) {
					return mapping.findForward("sessiontimeouterror");
				}	
				
				// check transition
				prevOpeTime = ((GenericForm) form).getOperationTime();
	
				if (!checkTransition(form, request)) {
	
					request.setAttribute("viewBean", form);
					return mapping.findForward("criticalerror");
				}
				
			executeType = ((GenericForm) form).getExecuteType();

			if (executeType.equals("")|| executeType.equals(Constant.EXEC_TYPE_SCREEN)) {
				af = this.executeScreen(mapping, form, request, response);
			} else if (executeType.equals(Constant.EXEC_TYPE_CSV)) {
				af = this.executeCSV(mapping, form, request, response);
				request.getSession().setAttribute(Constant.SESSION_PREOPETIME, prevOpeTime);
				((GenericForm) form).setOperationTime(prevOpeTime);
			} else if(executeType.equals(Constant.EXEC_TYPE_XLS)){
				af = this.executeXLS(mapping, form, request, response);
				request.getSession().setAttribute(Constant.SESSION_PREOPETIME, prevOpeTime);
				((GenericForm) form).setOperationTime(prevOpeTime);
			} else {
				LogWriter.error("Execute type is wrong. ExecuteType="+ executeType, Constant.LOGGER_COMMON);
			}

			/* check returnType */
			gForm = ((GenericForm) form);
			response.setCharacterEncoding("UTF-8");
			response.setContentType("text/html; charset=UTF-8");
			
		} catch (Exception e) {
			e.printStackTrace();
			LogWriter.error("Class: GenericAbstractAction method[execute] : " + e.toString(), Constant.LOGGER_COMMON);
			request.setAttribute("exception", e);
			return mapping.findForward("error");
			
		}
		return af;
	}

	private ActionForward executeScreen(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		String forwardJsp = null;
		GenericForm srcform = null;
		GenericDto dto = null;

		try {

			srcform = (GenericForm) form;			

			// Call Pre process method
			executeScreenPreProcess(mapping, srcform, request, response);

			// populate form to dto.
			dto = srcform.populateFormToDto(srcform);

			// Call EventFactory
			EventFactory eventfactory = new EventFactory();
			dto = eventfactory.executeBL(srcform.getBlClassName(), 
										srcform.getEventName(), 
										dto);

			// populate dto to form.
			srcform = srcform.populateDtoToForm(dto, srcform);

			// Call Post process method
			executeScreenPostProcess(mapping, srcform, form, request, response);

			// Get path to forward
			forwardJsp = srcform.getService_id();
			request.setAttribute("viewBean", srcform);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw new Exception();
		}

		return (mapping.findForward(forwardJsp));

	}

	private ActionForward executeCSV(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		GenericForm srcform = null;
		String forwardJsp = null;
		PrintWriter writer = null;
		ArrayList list = null;
		GenericDto dto = null;

		try {

			srcform = (GenericForm) form;

			// Call Pre process method
			executeScreenPreProcess(mapping, srcform, request, response);

			// populate form to dto.
			dto = srcform.populateFormToDto(srcform);

			// Call EventFactory
			EventFactory eventfactory = new EventFactory();
			dto = eventfactory.executeBL(srcform.getBlClassName(), srcform
					.getEventName(), dto);

			// populate dto to form.
			srcform = srcform.populateDtoToForm(dto, srcform);

			// Call Post process method
			executeScreenPostProcess(mapping, srcform, form, request, response);

			list = srcform.getReportData();

			srcform.setReturnType(null);

			if (list != null) {
				// Export CSV
				StringBuffer sb = new StringBuffer();
				sb.append(srcform.reportName);
				sb.append(new java.text.SimpleDateFormat("yyMMddhhmmss")
						.format(new java.util.Date()));
				sb.append(".csv");
				String fileName = sb.toString();

				// Set response header
				response.setContentType("application/octet-stream;charset=UTF-8");
				response.setHeader("Pragma", "");
				response.setHeader("Cache-Control", "");
				response.setHeader("Content-Disposition",
						"attachment; filename=" + fileName);
				// Get Print Writer
				writer = response.getWriter();
				Iterator it = list.iterator();
				while (it.hasNext()) {
					writer.println((String) it.next());
				}
			} else {
				// Has error
				forwardJsp = srcform.getService_id();
				request.setAttribute("viewBean", srcform);
			}

		} catch (Exception e) {
			try {
				if (writer != null) {
					writer.close();
				}
			} catch (Exception e2) {
				e2.printStackTrace();
				LogWriter.error("Execute CSV have error : " + e2.getMessage(), Constant.LOGGER_COMMON);
			}

			request.setAttribute("exception", e);
			return mapping.findForward("error");
		}

		try {
			// next disp forward
			if (list != null) {
				return null;
			} else {
				return mapping.findForward(forwardJsp);
			}
		} catch (Exception e) {
			request.setAttribute("exception", e);
			return mapping.findForward("error");
		}

	}
	
	private ActionForward executeXLS(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		GenericForm srcform = null;
		String forwardJsp = null;
		PrintWriter writer = null;
		HSSFWorkbook wb = null;
		GenericDto dto = null;

		try {

			srcform = (GenericForm) form;

			// Call Pre process method
			executeScreenPreProcess(mapping, srcform, request, response);

			// populate form to dto.
			dto = srcform.populateFormToDto(srcform);

			// Call EventFactory
			EventFactory eventfactory = new EventFactory();
			dto = eventfactory.executeBL(srcform.getBlClassName(), srcform
					.getEventName(), dto);

			// populate dto to form.
			srcform = srcform.populateDtoToForm(dto, srcform);

			// Call Post process method
			executeScreenPostProcess(mapping, srcform, form, request, response);

			wb = srcform.getWorkbook();	
			
			srcform.setExecuteType("");
			
			if (wb != null) {
				// Export XLS
				StringBuffer sb = new StringBuffer();
				sb.append(srcform.reportName);
				sb.append("_");
				Locale.setDefault(new Locale("en","EN"));
				sb.append(new java.text.SimpleDateFormat("yyyyMMddhhmmss")
						.format(new java.util.Date()));
				sb.append(".xls");
				String fileName = sb.toString();
	
				// Set response header
				response.setContentType("application/vnd.ms-excel;charset=UTF-8");
				response.setHeader("Content-Disposition", "attachment; filename="+ fileName);
				
				HSSFWorkbook workbook = wb;
			    ServletOutputStream out = response.getOutputStream();
			    workbook.write(out);
			    out.flush();
			    out.close();
				
			
			} else {
				 //Has error
				forwardJsp = srcform.getService_id();
				request.setAttribute("viewBean", srcform);
			}

		} catch (Exception e) {			
			LogWriter.error("Execute XLS have error : " + e.getMessage(), Constant.LOGGER_COMMON);
			request.setAttribute("exception", e);
			return mapping.findForward("error");
		}
		
		try {
			// next disp forward
			if (wb != null) {
				return null;
			} else {
				return mapping.findForward(forwardJsp);
			}
		} catch (Exception e) {
			request.setAttribute("exception", e);
			return mapping.findForward("error");
		}

	}	

	protected abstract void executeScreenPreProcess(ActionMapping mapping,
			GenericForm srcform, HttpServletRequest request,
			HttpServletResponse response) throws Exception;

	protected abstract void executeScreenPostProcess(ActionMapping mapping,
			GenericForm srcform, ActionForm form,  HttpServletRequest request,
			HttpServletResponse response) throws Exception;


}
